(** Bombs-Must-Detonate: Lexer Generator **)
{
  open Bmdparse (** Parser generator defined in bmdparse.mly **)
  let line_count = ref 1
}

let digit = ['0'-'9']
let identifier = ['a'-'z' 'A'-'Z' '_']['a'-'z' 'A'-'Z' '_' '0'-'9']*

rule bmd_lang = parse
  | "//"            { line_comment lexbuf }
  | "/*"            { block_comment lexbuf }
  | '\n'            { let _ = line_count := !line_count + 1 in bmd_lang lexbuf  }
  | ' '             { bmd_lang lexbuf  }
  | '\t'            { bmd_lang lexbuf  }
  | '\r'            { bmd_lang lexbuf  }
  | "include"       { INCLUDE }
  | "int"           { INT }
  | "float"         { FLOAT }
  | "string"        { STRING }
  | "bool"          { BOOL }
  | "void"          { VOID }
  | "enum"          { ENUM }
  | "struct"        { STRUCT }
  | "list"          { LIST }
  | "array"         { ARRAY }
  | "ref"           { REF }
  | "remotable"     { REMOTABLE }
  | '('             { LPAREN }
  | ')'             { RPAREN }
  | '['             { LBRACKET }
  | ']'             { RBRACKET }
  | '<'             { LT }
  | '>'             { GT }
  | '{'             { LCURLBRACKET }
  | '}'             { RCURLBRACKET }
  | '\"'            { QUOTES }
  | ','             { COMMA }
  | '.'             { PERIOD }
  | ';'             { SEMICOLON }
  | ':'             { COLON }
  | '!'             { EXCLAMATION }
  | '~'             { TILDE }
  | '$'             { DOLLAR }
  | digit+ as inum  { INTVAL (int_of_string inum) }
  | digit+ '.' digit* as fnum
                    { FLOATVAL (float_of_string fnum) }
  | "true"          { TRUE }
  | "false"         { FALSE }
  | "nil"           { NIL }
  | "="             { EQUALS }
  | "not"           { NOT }
  | "if"            { IF }
  | "else"          { ELSE }
  | "while"         { WHILE }
  | "for"           { FOR }
  | "break"         { BREAK }
  | "continue"      { CONTINUE }
  | "do"            { DO }
  | "car"           { CAR }
  | "cdr"           { CDR }
  | "trunc"         { TRUNC }
  | "null"          { NULL }
  | "and"           { AND }
  | "or"            { OR }
  | "&&"            { AND }
  | "||"            { OR }
  | "nor"           { NOR }
  | "xor"           { XOR }
  | "nand"          { NAND }
  | '+'             { ADD }
  | '-'             { SUB }
  | '*'             { MUL }
  | '/'             { DIV }
  | "#/"            { IDIV }
  | '%'             { MOD }
  | '@'             { CONCAT }
  | "break"         { BREAK }
  | "continue"      { CONTINUE }
  | "return"        { RETURN }
  | "template"      { TEMPLATE }
  | "stateMachine"  { STATEMACHINE }
  | "state"         { STATE }
  | "stateMachineInit"       
                    { FSMINIT }
  | "stateTransition"    
                    { TRANSITION }
  | "transitionPredicates"
                    { PREDICATE }
  | "transitionTargets"
                    { TARGET }
  | eof             { let _ = line_count := 0 in ENDOFFILE }
  | identifier as s { IDENTIFIER s }
  | '\"' [^'\"']* '\"' as s 
                    { 
		      try
			STR (String.sub s 1 ((String.length s)-2)) 
		      with (Invalid_argument _) ->
		        STR "" }
  | _ { let _ = line_count := 0 in ENDOFFILE }

and line_comment = parse
  | '\n'            { let _ = line_count := !line_count + 1 in bmd_lang lexbuf  }
  | eof             { let _ = line_count := 0 in ENDOFFILE }
  | _               { line_comment lexbuf }

and block_comment = parse
  | "*/"            { bmd_lang lexbuf  }
  | eof             { let _ = line_count := 0 in ENDOFFILE }
  | '\n'            { let _ = line_count := !line_count + 1 in block_comment lexbuf }
  | _               { block_comment lexbuf }



